package utils;


import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import java.util.concurrent.Callable;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author shilei
 * @create 2020-11-24 17:55
 */
@Component
public class AsyncUtils {

    private static final ThreadPoolTaskExecutor service = new ThreadPoolTaskExecutor();

    static {
        int threadCount = Runtime.getRuntime().availableProcessors();
        service.setCorePoolSize(threadCount);//核心池大小
        service.setMaxPoolSize(threadCount);//最大线程数
        service.setQueueCapacity(128);//队列程度
        service.setAllowCoreThreadTimeOut(true);
        service.setKeepAliveSeconds(300);//线程空闲时间
        service.setThreadNamePrefix("AsyncTask-Thread-");//线程前缀名称
        service.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());//配置拒绝策略
        service.initialize();
    }

    /**
     * 执行异步调用-无返回值
     *
     * @param obj        要调用的实例化对象
     * @param methodName 方法名
     */
    public static void call(Object obj, String methodName) {
        call(obj, methodName, null);
    }

    /**
     * 执行异步调用-无返回值
     *
     * @param obj        要调用的实例化对象
     * @param methodName 方法名
     * @param paraTypes  参数类型
     */
    public static void call(Object obj, String methodName, Class[] paraTypes) {
        call(obj, methodName, paraTypes, null);
    }

    /**
     * 执行异步调用-无返回值
     *
     * @param obj        要调用的实例化对象
     * @param methodName 方法名
     * @param paraTypes  参数类型
     * @param paraValues 参数值
     */
    public static void call(Object obj, String methodName, Class[] paraTypes, Object[] paraValues) {
        if (obj == null) {
            throw new NullPointerException("Illegal parameter [obj is null]");
        }
        if (methodName == null || methodName.trim().isEmpty()) {
            throw new NullPointerException("Illegal parameter [methodName is null or empty]");
        }
        service.submit(getRunnable(obj, methodName, paraTypes, paraValues));
    }

    /**
     * 获取异步执行 Runnable
     *
     * @param obj        要调用的实例化对象
     * @param methodName 方法名
     * @param paraTypes  参数类型
     * @param paraValues 参数值
     * @return Runnable
     */
    private static Runnable getRunnable(final Object obj, final String methodName, final Class[] paraTypes, final Object[] paraValues) {
        return () -> {
            try {
                obj.getClass().getMethod(methodName, paraTypes).invoke(obj, paraValues);
            } catch (Exception e) {
                throw new RuntimeException(String.format("异步方法执行异常:实例对象:%s-方法名:%s-异常信息:%s", obj, methodName, e.getMessage()));
            }
        };
    }

    /**
     * 获取异步执行 Callable
     *
     * @param obj        要调用的实例化对象
     * @param methodName 方法名
     * @param paraTypes  参数类型
     * @param paraValues 参数值
     * @return Callable
     */
    private static Callable<Object> getCallable(final Object obj, final String methodName, final Class[] paraTypes, final Object[] paraValues) {
        return () -> {
            try {
                return obj.getClass().getMethod(methodName, paraTypes).invoke(obj, paraValues);
            } catch (Exception e) {
                throw new RuntimeException(String.format("异步方法执行异常:实例对象:%s-方法名:%s-异常信息:%s", obj, methodName, e.getMessage()));
            }
        };
    }
}

